/*
 * CCVisu is a tool for visual graph clustering
 * and general force-directed graph layout.
 * This file is part of CCVisu.
 *
 * Copyright (C) 2005-2012  Dirk Beyer
 *
 * CCVisu is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * CCVisu is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with CCVisu; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Please find the GNU Lesser General Public License in file
 * license_lgpl.txt or http://www.gnu.org/licenses/lgpl.txt
 *
 * Dirk Beyer    (firstname.lastname@uni-passau.de)
 * University of Passau, Bavaria, Germany
 */
package org.sosy_lab.ccvisu.graph;

import java.awt.Color;


/**
 * Represents a vertex of the graph, including name, id,
 * and several attributes.
 */
public class GraphVertex implements Comparable<GraphVertex> {

  private static Color   DEFAULT_COLOR = Color.green;

  // Name of the vertex must be unique within the parent graph
  private String         name        = "";

  // Label that will be displayed
  private String         label       = "";

  private String         tooltip     = "";

  /** The color in which this vertex is to be printed. */
  private Color          color       = DEFAULT_COLOR;

  private Shape          shape       = Shape.DISC;

  /** True if the vertex shall never be included in the visualization. */
  private boolean        auxiliary   = false;

  /** Position of this vertex. */
  private Position       position    = new Position();

  private int            id          = 0;

  /** True if the vertex is the source vertex of an edge. */
  private boolean        isSource    = false;

  /** (Weighted) Edge degree of the vertex. */
  private float          degree      = 0.0f;
  private float          degreeOut   = 0.0f;

  private NameVisibility showName    = new NameVisibility();

  /**
   * True if the vertex shall be displayed. Used for partial display of vertices
   * during zoom.
   */
  private boolean        showVertex  = true;

  /** True if the position of this node should not be changed by the layouter. */
  private boolean        fixedPos    = false;

  /** True if the vertex is reflexive and a self loop should be drawn. */
  private boolean        hasSelfLoop = false;

  public enum Shape {
    DISC, BOX, RBOX, FIXED_SIZE_BOX, FILLER_RECT
  }

  public GraphVertex(String name) {
    assert(name != null);
    this.name = name;
  }

  public GraphVertex(String name, int id) {
    this(name);
    assert(id >= 0);

    this.id = id;
  }

  public GraphVertex(String name, boolean auxiliary) {
    this(name);
    this.auxiliary = auxiliary;
  }

  public GraphVertex(String name, Position position, float degree) {
    this(name);
    assert(position != null);

    this.setPosition(position);
    this.degree = degree;
  }

  public GraphVertex(GraphVertex oldVertex) {
    name = oldVertex.name;
    label = oldVertex.label;
    tooltip = oldVertex.tooltip;
    id = oldVertex.id;
    isSource = oldVertex.isSource;
    degree = oldVertex.degree;
    degreeOut = oldVertex.degreeOut;
    color = oldVertex.color;
    shape = oldVertex.shape;
    showVertex = oldVertex.showVertex;
    auxiliary = oldVertex.auxiliary;
    fixedPos = oldVertex.fixedPos;
    hasSelfLoop = oldVertex.hasSelfLoop;

    showName = new NameVisibility(oldVertex.showName);
    position = new Position(oldVertex.position);
  }

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  /**
   * @return The Position element of this class.
   *         The object returned is the object stored in this Vertex.
   */
  public Position getPosition() {
    return position;
  }

  /**
   * @param position The new position of this vertex.
   * The position is not copied and stored directly in this Vertex.
   */
  public void setPosition(Position pos) {
    this.position = pos;
  }

  /**
   * Returns the euclidean distance from this vertex to a given vertex.
   *
   * @param vertex The other vertex. Must not be <code>null</code>.
   */
  public float distanceTo(GraphVertex vertex) {
    assert vertex != null;
    return distanceTo(vertex.getPosition());
  }

  /**
   * Returns the euclidean distance from this vertex to a given position.
   *
   * @param pos The position. Must not be <code>null</code>.
   */
  public float distanceTo(Position pos) {
    assert pos != null;
    return getPosition().distanceTo(pos);
  }

  public String getLabel() {
    if ((label == null) || (label.equals(""))) {
      return name;
    } else {
      return label;
    }
  }

  public void setLabel(String label) {
    this.label = label;
  }

  public String getName() {
    return name;
  }

  public Color getColor() {
    return color;
  }

  /**
   * Sets this vertex to a given color.
   *
   * @param color The new color of this vertex. Must not be null.
   */
  public void setColor(Color color) {
    assert color != null;
    this.color = color;
  }

  /**
   * Sets the default color for this vertex.
   */
  public void resetColor() {
    this.color = DEFAULT_COLOR;
  }

  public float getDegree() {
    return degree;
  }

  public void setDegree(float degree) {
    this.degree = degree;
  }

  public float getDegreeOut() {
    return degreeOut;
  }

  public void setDegreeOut(float degreeOut) {
    this.degreeOut = degreeOut;
  }

  /**
   * @return the shape
   */
  public Shape getShape() {
    return shape;
  }

  /**
   * @param shape the shape to set
   */
  public void setShape(Shape shape) {
    this.shape = shape;
  }

  /**
   * Returns whether the label of this vertex is to be shown.
   */
  public boolean isShowName() {
    return showName.isVisible();
  }

  /**
   * Returns whether this vertex is to be shown.
   */
  public boolean isShowVertex() {
    return showVertex;
  }

  public void setShowVertex(boolean showVertex) {
    this.showVertex = showVertex;
  }

  /** Returns whether this is an auxiliary vertex, which is never to be visualized. */
  public boolean isAuxiliary() {
    return auxiliary;
  }

  public boolean isSource() {
    return isSource;
  }

  public void setIsSource(boolean isSource) {
    this.isSource = isSource;
  }

  /**
   * Sets the a given visibility priority of this to either <code>true</code>
   * or <code>false</code>. Note that setting the visibility of one priority
   * to false is not equivalent to unsetting a priority.
   */
  public void setShowName(NameVisibility.Priority priority, boolean showName) {
    this.showName.setVisibility(priority, showName);
  }

  /**
   * Sets a show name priority equal to that of the given {@link GraphVertex}.
   */
  public void setShowName(GraphVertex vertex) {
    showName = new NameVisibility(vertex.showName);
  }

  public void unsetShowName(NameVisibility.Priority priority) {
    showName.unsetVisibility(priority);
  }

  public void resetShowName() {
    showName.reset();
  }

  public void setTooltip(String tooltip) {
    this.tooltip = tooltip;
  }

  public String getTooltip() {
    return tooltip;
  }

  public boolean hasFixedPos() {
    return fixedPos;
  }

  public void setFixedPos(boolean fixedPos) {
    this.fixedPos = fixedPos;
  }

  public boolean hasSelfLoop() {
    return hasSelfLoop;
  }

  @Override
  public String toString() {
    return getName();
  }

  @Override
  public int compareTo(GraphVertex other) {
    int result = this.getName().compareTo(other.getName());
    if (result == 0) {
      result = Integer.compare(this.getId(), other.getId());
    }
    return result;
  }
}
